package com.java.activiti.controller;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.FormService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.ManagementService;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.form.TaskFormData;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.spring.ProcessEngineFactoryBean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.java.activiti.model.Group;
import com.java.activiti.model.Leave;
import com.java.activiti.model.MemberShip;
import com.java.activiti.model.MyTask;
import com.java.activiti.model.PageInfo;
import com.java.activiti.model.User;
import com.java.activiti.service.LeaveService;
import com.java.activiti.util.DateJsonValueProcessor;
import com.java.activiti.util.ResponseUtil;

/**
 * 历史流程批注管理
 * 
 * @author Administrator
 *
 */
@Controller
@RequestMapping("/task")
public class TaskController {

	// 引入activiti自带的Service接口
	@Resource
	private TaskService taskService;
	
	@Resource
	private RepositoryService repositoryService;
	
	@Resource
	private RuntimeService runtimeService;
	
	@Resource
	private FormService formService;
	
	@Resource
	private LeaveService leaveService;
	
	@Resource
	private HistoryService historyService;

	@Resource
	private ProcessEngineConfiguration processEngineConfiguration;  
	@Resource
	private ProcessEngineFactoryBean processEngineb;  
	/**
	 * 查询历史流程批注
	 * 
	 * @param response
	 * @param processInstanceId
	 *            流程ID
	 * @return
	 * @throws Exception 
	 */
	@RequestMapping("/listHistoryCommentWithProcessInstanceId")
	public String listHistoryCommentWithProcessInstanceId(
			HttpServletResponse response, String processInstanceId) throws Exception {
		if (processInstanceId == null) {
			return null;
		}
		List<Comment> commentList = taskService
				.getProcessInstanceComments(processInstanceId);
		// 改变顺序，按原顺序的反向顺序返回list
		Collections.reverse(commentList); //集合元素反转
		JsonConfig jsonConfig = new JsonConfig();
		jsonConfig.registerJsonValueProcessor(java.util.Date.class,
			//时间格式转换
				new DateJsonValueProcessor("yyyy-MM-dd hh:mm:ss"));
		JSONObject result = new JSONObject();
		JSONArray jsonArray = JSONArray.fromObject(commentList, jsonConfig);
		result.put("rows", jsonArray);
		ResponseUtil.write(response, result);
		return null;
	}
	
	/**
	 * 重定向审核处理页面
	 * @param taskId
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/redirectPage")
	public String redirectPage(String taskId,HttpServletResponse response)throws Exception{
		TaskFormData formData=formService.getTaskFormData(taskId);
		String url=formData.getFormKey();
		System.out.println("*********************"+url);
		JSONObject result=new JSONObject();
		result.put("url", url);
		ResponseUtil.write(response, result);
		return null;
	}
	

	/**
	 * 待办流程分页查询
	 * @param response
	 * @param page 当前页数
	 * @param rows 每页显示页数
	 * @param s_name 流程名称
	 * @param userId 流程ID
	 * @return
	 * @throws Exception 
	 */
	@RequestMapping("/taskPage")
	public String taskPage(HttpServletResponse response,String page,String rows,String s_name,String userId) throws Exception{
		if(s_name==null){
			s_name="";
		}
		PageInfo pageInfo=new PageInfo();
		Integer pageSize=Integer.parseInt(rows);
		pageInfo.setPageSize(pageSize);
		if(page==null||page.equals("")){
			page="1";
		}
		pageInfo.setPageIndex((Integer.parseInt(page)-1)*pageInfo.getPageSize());
		// 获取总记录数
		System.out.println("用户ID："+userId+"\n"+"名称:"+s_name);
		long total=taskService.createTaskQuery()
				.taskCandidateGroup(userId)
				.taskNameLike("%"+s_name+"%")
				.count(); // 获取总记录数
		//有想法的话，可以去数据库观察  ACT_RU_TASK 的变化
		List<Task> taskList=taskService.createTaskQuery()
				 // 根据用户id查询
				.taskCandidateGroup(userId)
				// 根据任务名称查询
				.taskNameLike("%"+s_name+"%") 
				// 返回带分页的结果集合
				.listPage(pageInfo.getPageIndex(), pageInfo.getPageSize()); 
		//这里需要使用一个工具类来转换一下主要是转成JSON格式
		List<MyTask> MyTaskList=new ArrayList<MyTask>();
		for(Task t:taskList){
			MyTask myTask=new MyTask();
			myTask.setId(t.getId());
			myTask.setName(t.getName());
			myTask.setCreateTime(t.getCreateTime());
			MyTaskList.add(myTask);
		}
		JsonConfig jsonConfig=new JsonConfig();
		jsonConfig.registerJsonValueProcessor(java.util.Date.class, new DateJsonValueProcessor("yyyy-MM-dd hh:mm:ss"));
		JSONObject result=new JSONObject();
		JSONArray jsonArray=JSONArray.fromObject(MyTaskList,jsonConfig);
		result.put("rows", jsonArray);
		result.put("total", total);
		ResponseUtil.write(response, result);
		return null;
	}
	/**
	 * 查询当前流程图
	 * @return
	 */
	@RequestMapping("/showCurrentView")
	public ModelAndView showCurrentView(HttpServletResponse response,String taskId){
		//视图
		ModelAndView mav=new ModelAndView();
		
		Task task=taskService.createTaskQuery() // 创建任务查询
				.taskId(taskId) // 根据任务id查询
				.singleResult(); 
		 // 获取流程定义id
		String processDefinitionId=task.getProcessDefinitionId();
		ProcessDefinition processDefinition=repositoryService.createProcessDefinitionQuery() // 创建流程定义查询
				// 根据流程定义id查询
				.processDefinitionId(processDefinitionId) 
				.singleResult(); 
		// 部署id
		mav.addObject("deploymentId",processDefinition.getDeploymentId()); 
		mav.addObject("diagramResourceName", processDefinition.getDiagramResourceName()); // 图片资源文件名称
		
	    ProcessDefinitionEntity	processDefinitionEntity=(ProcessDefinitionEntity) 
	    		repositoryService.getProcessDefinition(processDefinitionId); 
	    // 获取流程实例id
	    String processInstanceId=task.getProcessInstanceId(); 
	    // 根据流程实例id获取流程实例
	    ProcessInstance pi=runtimeService.createProcessInstanceQuery() 
	    		.processInstanceId(processInstanceId)
	    		.singleResult();
	    
	    // 根据活动id获取活动实例
	    ActivityImpl activityImpl=processDefinitionEntity.findActivity(pi.getActivityId()); 
	    //整理好View视图返回到显示页面
	    mav.addObject("x", activityImpl.getX()); // x坐标
	    mav.addObject("y", activityImpl.getY()); // y坐标
	    mav.addObject("width", activityImpl.getWidth()); // 宽度
	    mav.addObject("height", activityImpl.getHeight()); // 高度
		mav.setViewName("page/currentView");
		return mav;
	}
	
	/**
	 * 查询当前流程图
	 * @return
	 * @throws IOException 
	 */
	@RequestMapping("/showHisCurrentView")
	public ModelAndView showHisCurrentView(HttpServletResponse response,String taskId) throws IOException{		
		//视图
		ModelAndView mav=new ModelAndView();
		/*HistoricProcessInstance hiprocessInstance=historyService.createHistoricProcessInstanceQuery()//创建流程实例查询
                .processInstanceId(taskId)//使用流程实例ID查询
                .singleResult();*/
		
		/*ProcessInstance processInstance = runtimeService  
		        .createProcessInstanceQuery()  
		        .processInstanceId(taskId)  
		        .singleResult();*/
		//System.out.println("processInstance======="+processInstance);
		HistoricTaskInstance hti=historyService.createHistoricTaskInstanceQuery()
				.taskId(taskId)
				.singleResult();
				
		List<HistoricActivityInstance> hiactiviInstance = historyService.createHistoricActivityInstanceQuery()
	            .processInstanceId(hti.getProcessInstanceId())
	            .orderByHistoricActivityInstanceStartTime().asc() /* .orderByActivityId().asc() */
                .list();
		HistoricActivityInstance list=hiactiviInstance.get(hiactiviInstance.size()-1);//获取最后一条数据
		//System.out.println("list====="+list.getActivityId());
		/*for (HistoricActivityInstance hai : hiactiviInstance) {
	        System.out.println("hai====="+hai.getActivityId());
	    }*/
		//System.out.println("proc====="+hti.getProcessInstanceId());
		//System.out.println("hti====="+hti.getTaskDefinitionKey());
		//System.out.println("hiactiviInstance====="+hiactiviInstance.getActivityId());
		String processDefinitionId=hti.getProcessDefinitionId();
		//String processDefinitionId = processInstance.getProcessDefinitionId();  
		//将流程定义id传到页面，用于图形显示  
		//mav.addObject("processDefinitionId", processInstance.getProcessDefinitionId()); 
		//根据流程实例id processInstanceId,获取当前结点  		
		
		//String activityId = hitaskInstance.getActivityId();  
		//根据流程定义id查询流程定义对象  
		ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) repositoryService  
		        .getProcessDefinition(processDefinitionId); 
				
		mav.addObject("deploymentId",processDefinitionEntity.getDeploymentId()); // 部署id
		mav.addObject("diagramResourceName", processDefinitionEntity.getDiagramResourceName()); // 图片资源文件名称

		//从流程定义实体对象查询结点的坐标和宽高  
		ActivityImpl activityImpl = processDefinitionEntity.findActivity(list.getActivityId()); 
		mav.addObject("x", activityImpl.getX()); // x坐标
	    mav.addObject("y", activityImpl.getY()); // y坐标
	    mav.addObject("width", activityImpl.getWidth()); // 宽度
	    mav.addObject("height", activityImpl.getHeight()); // 高度
		mav.setViewName("page/currentView");
		return mav;  	       
	   }

	 
	
	/**
	 * 查询历史批注
	 * @param response
	 * @param taskId 流程ID  
	 * @return
	 * @throws Exception 
	 */
	@RequestMapping("/listHistoryComment")
	public String listHistoryComment(HttpServletResponse response,String taskId) throws Exception{
		if(taskId==null){
			taskId="";
		}
		HistoricTaskInstance hti=historyService.createHistoricTaskInstanceQuery()
				.taskId(taskId)
				.singleResult();
		JsonConfig jsonConfig=new JsonConfig();
		JSONObject result=new JSONObject();
		List<Comment> commentList=null;
		if(hti!=null){
		    commentList=taskService.getProcessInstanceComments(hti.getProcessInstanceId()); 
			// 集合元素反转
			Collections.reverse(commentList); 
			
			//日期格式转换
			jsonConfig.registerJsonValueProcessor(java.util.Date.class, new DateJsonValueProcessor("yyyy-MM-dd hh:mm:ss"));
		}
		JSONArray jsonArray=JSONArray.fromObject(commentList,jsonConfig);
		result.put("rows", jsonArray);
		ResponseUtil.write(response, result);
		return null;
	}
	
	/**
	 * 审批
	 * @param taskId 任务id
	 * @param leaveDays 请假天数
	 * @param comment 批注信息
	 * @param state 审核状态 1 通过 2 驳回
	 * @param response
	 * @param session
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/audit_bz")
	public String audit_bz(String taskId,Integer leaveDays,String comment,Integer state,HttpServletResponse response,HttpSession session)throws Exception{
		//首先根据ID查询任务
		Task task=taskService.createTaskQuery() // 创建任务查询
		        .taskId(taskId) // 根据任务id查询
		        .singleResult();
		Map<String,Object> variables=new HashMap<String,Object>();
		//取得角色用户登入的session对象
		MemberShip currentMemberShip=(MemberShip) session.getAttribute("currentMemberShip");
		//取出用户，角色信息
		User currentUser=currentMemberShip.getUser();
		Group currentGroup=currentMemberShip.getGroup();
		if(currentGroup.getName().equals("总裁")||currentGroup.getName().equals("副总裁")){
			if(state==1){
				String leaveId=(String) taskService.getVariable(taskId, "leaveId");
				Leave leave=leaveService.findById(leaveId);
				leave.setState("审核通过");
				// 更新审核信息
				leaveService.updateLeave(leave); 
				variables.put("msg", "通过");
			}else{
				String leaveId=(String) taskService.getVariable(taskId, "leaveId");
				Leave leave=leaveService.findById(leaveId);
				leave.setState("审核未通过");
				// 更新审核信息
				leaveService.updateLeave(leave); 
				variables.put("msg", "未通过");
			}
		}
		if(state==1){
			variables.put("msg", "通过");
		}else{
			String leaveId=(String) taskService.getVariable(taskId, "leaveId");
			Leave leave=leaveService.findById(leaveId);
			leave.setState("审核未通过");
			// 更新审核信息
			leaveService.updateLeave(leave); 
			variables.put("msg", "未通过");
		}
		// 设置流程变量
		variables.put("dasy", leaveDays); 
		 // 获取流程实例id
		String processInstanceId=task.getProcessInstanceId();
		// 设置用户id
		Authentication.setAuthenticatedUserId(currentUser.getFirstName()+currentUser.getLastName()+"["+currentGroup.getName()+"]"); 
		// 添加批注信息
		taskService.addComment(taskId, processInstanceId, comment); 
		// 完成任务
		taskService.complete(taskId, variables); 
		JSONObject result=new JSONObject();
		result.put("success", true);
		ResponseUtil.write(response, result);
		return null;
	}
	
	/**
	 * 查詢流程正常走完的历史流程表 :  act_hi_actinst
	 * @param response
	 * @param rows
	 * @param page
	 * @param s_name  
	 * @param groupId
	 * @return
	 * @throws Exception 
	 */
	@RequestMapping("/finishedList")
	public String finishedList(HttpServletResponse response,String rows,String page,String s_name,String groupId) throws Exception{
		//为什么要这样呢？因为程序首次运行进入后台时，
		//s_name必定是等于null的，如果直接这样填写进查询语句中就会出现  % null %这样就会导致查询结果有误
		if(s_name==null){
			s_name="";
		}
		PageInfo pageInfo=new PageInfo();
		Integer pageSize=Integer.parseInt(rows);
		pageInfo.setPageSize(pageSize);
		if(page==null||page.equals("")){
			page="1";
		}
		pageInfo.setPageIndex((Integer.parseInt(page)-1)*pageSize);
											//创建流程历史实例查询
		List<HistoricTaskInstance> histList=historyService.createHistoricTaskInstanceQuery()
				.taskCandidateGroup(groupId)//根据角色名称查询
				.taskNameLike("%"+s_name+"%")
				.listPage(pageInfo.getPageIndex(), pageInfo.getPageSize());
		long histCount=historyService.createHistoricTaskInstanceQuery()
				.taskCandidateGroup(groupId)
				.taskNameLike("%"+s_name+"%")
				.count();
		List<MyTask> taskList=new ArrayList<MyTask>();
		//这里递出没有用的字段，免得给前端页面做成加载压力
		for(HistoricTaskInstance hti:histList){
			MyTask myTask=new MyTask();
			myTask.setId(hti.getId());
			myTask.setName(hti.getName());
			myTask.setCreateTime(hti.getCreateTime());
			myTask.setEndTime(hti.getEndTime());
			taskList.add(myTask);
		}
		JsonConfig jsonConfig=new JsonConfig();
		jsonConfig.registerJsonValueProcessor(java.util.Date.class, new DateJsonValueProcessor("yyyy-MM-dd hh:mm:ss"));
		JSONObject result=new JSONObject();
		JSONArray jsonArray=JSONArray.fromObject(taskList,jsonConfig);
		result.put("rows", jsonArray);
		result.put("total",histCount);
		ResponseUtil.write(response, result);
		return null;
	}
	/**
	 * 根据任务id查询流程实例的具体执行过程
	 * @param taskId
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/listAction")
	public String listAction(String taskId,HttpServletResponse response)throws Exception{
	 if(taskId!=null){//由于easyui会主动查询，没有id时会报错
		HistoricTaskInstance hti=historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
		String processInstanceId=hti.getProcessInstanceId(); // 获取流程实例id
		List<HistoricActivityInstance> haiList=historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list();
		JsonConfig jsonConfig=new JsonConfig();
		jsonConfig.registerJsonValueProcessor(java.util.Date.class, new DateJsonValueProcessor("yyyy-MM-dd hh:mm:ss"));
		JSONObject result=new JSONObject();
		JSONArray jsonArray=JSONArray.fromObject(haiList,jsonConfig);
		result.put("rows", jsonArray);
		ResponseUtil.write(response, result);
		}
		return null;
	}
	
	/**----------------------------------------------*/
	/**
	 * 高亮显示流程过程
	 */
	 @RequestMapping("queryProPlan")  
	    public void queryProPlan(HttpServletResponse response,String taskId) throws IOException{  
	        
		 HistoricTaskInstance hti=historyService.createHistoricTaskInstanceQuery()
					.taskId(taskId)
					.singleResult();   
		    String processInstanceId = hti.getProcessInstanceId(); 
	        //System.out.println("processInstanceId=="+processInstanceId);
	        //获取历史流程实例  
	        HistoricProcessInstance processInstance =  historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();  
	       
	        //System.out.println("hti.getProcessDefinitionId()=="+processInstance.getProcessDefinitionId());
	        //获取流程图  
	        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());  
	        processEngineConfiguration = processEngineb.getProcessEngineConfiguration();  
	        Context.setProcessEngineConfiguration((ProcessEngineConfigurationImpl) processEngineConfiguration);  
	  
	        ProcessDiagramGenerator diagramGenerator = processEngineConfiguration.getProcessDiagramGenerator();  
	        ProcessDefinitionEntity definitionEntity = (ProcessDefinitionEntity)repositoryService.getProcessDefinition(processInstance.getProcessDefinitionId());  
	  
	        List<HistoricActivityInstance> highLightedActivitList =  historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list();  
	        //高亮环节id集合  
	        List<String> highLightedActivitis = new ArrayList<String>();  
	          
	        //高亮线路id集合  
	        List<String> highLightedFlows = getHighLightedFlows(definitionEntity,highLightedActivitList);  
	  
	        for(HistoricActivityInstance tempActivity : highLightedActivitList){  
	            String activityId = tempActivity.getActivityId();  
	            highLightedActivitis.add(activityId);  
	        }  
	  
	        //中文显示的是口口口，设置字体就好了  
	        InputStream imageStream = diagramGenerator.generateDiagram(bpmnModel, "png", highLightedActivitis,highLightedFlows,"宋体","宋体",null,1.0);  
	        //单独返回流程图，不高亮显示  
//	        InputStream imageStream = diagramGenerator.generatePngDiagram(bpmnModel);  
	        // 输出资源内容到相应对象  
	        byte[] b = new byte[1024];  
	        int len;  
	        while ((len = imageStream.read(b, 0, 1024)) != -1) {  
	            response.getOutputStream().write(b, 0, len);  
	        }  
	          
	    }  
	     /**  
	     * 获取需要高亮的线  
	     * @param processDefinitionEntity  
	     * @param historicActivityInstances  
	     * @return  
	     */  
	    private List<String> getHighLightedFlows(  
	            ProcessDefinitionEntity processDefinitionEntity,  
	            List<HistoricActivityInstance> historicActivityInstances) {  
	          
	        List<String> highFlows = new ArrayList<String>();// 用以保存高亮的线flowId  
	        for (int i = 0; i < historicActivityInstances.size() - 1; i++) {// 对历史流程节点进行遍历  
	            ActivityImpl activityImpl = processDefinitionEntity  
	                    .findActivity(historicActivityInstances.get(i)  
	                            .getActivityId());// 得到节点定义的详细信息  
	            List<ActivityImpl> sameStartTimeNodes = new ArrayList<ActivityImpl>();// 用以保存后需开始时间相同的节点  
	            ActivityImpl sameActivityImpl1 = processDefinitionEntity  
	                    .findActivity(historicActivityInstances.get(i + 1)  
	                            .getActivityId());  
	            // 将后面第一个节点放在时间相同节点的集合里  
	            sameStartTimeNodes.add(sameActivityImpl1);  
	            for (int j = i + 1; j < historicActivityInstances.size() - 1; j++) {  
	                HistoricActivityInstance activityImpl1 = historicActivityInstances  
	                        .get(j);// 后续第一个节点  
	                HistoricActivityInstance activityImpl2 = historicActivityInstances  
	                        .get(j + 1);// 后续第二个节点  
	                if (activityImpl1.getStartTime().equals(  
	                        activityImpl2.getStartTime())) {  
	                    // 如果第一个节点和第二个节点开始时间相同保存  
	                    ActivityImpl sameActivityImpl2 = processDefinitionEntity  
	                            .findActivity(activityImpl2.getActivityId());  
	                    sameStartTimeNodes.add(sameActivityImpl2);  
	                } else {  
	                    // 有不相同跳出循环  
	                    break;  
	                }  
	            }  
	            List<PvmTransition> pvmTransitions = activityImpl  
	                    .getOutgoingTransitions();// 取出节点的所有出去的线  
	            for (PvmTransition pvmTransition : pvmTransitions) {  
	                // 对所有的线进行遍历  
	                ActivityImpl pvmActivityImpl = (ActivityImpl) pvmTransition  
	                        .getDestination();  
	                // 如果取出的线的目标节点存在时间相同的节点里，保存该线的id，进行高亮显示  
	                if (sameStartTimeNodes.contains(pvmActivityImpl)) {  
	                    highFlows.add(pvmTransition.getId());  
	                }  
	            }  
	        }  
	        return highFlows;  
	    }  
}
